; qword invoke_sys_proc_x64( qword *pdwStack, qword dwNumArgs, qword dwProcAddr, qword dwCallConv )
_TEXT    SEGMENT
pdwStack = -32                     ; size = 8
dwNumArgs = -24                    ; size = 8
dwProcAddr = -16                   ; size = 8
dwCallConv = -8                    ; size = 8
invoke_sys_proc_x64 PROC STDCALL   ; invoke_sys_proc_x64
    push rbp
    mov rbp, rsp
    sub rsp, 32
    push rbx
    mov QWORD PTR dwNumArgs[rbp], rdx
    mov QWORD PTR pdwStack[rbp], rcx
    mov QWORD PTR dwProcAddr[rbp], r8
    mov QWORD PTR dwCallConv[rbp], r9
    mov rax, QWORD PTR dwNumArgs[rbp]
    mov rbx, QWORD PTR pdwStack[rbp]
    
    cmp rax, 0          ; how many args?
    je  SHORT _do_call

    mov rcx, QWORD PTR [rbx] ; get 1st arg
    add rbx, 8
    dec rax
    je  SHORT _do_call

    mov rdx, QWORD PTR [rbx] ; get 2nd arg
    add rbx, 8
    dec rax
    je  SHORT _do_call

    mov r8, QWORD PTR [rbx] ; get 3rd arg
    add rbx, 8
    dec rax
    je  SHORT _do_call

    mov r9, QWORD PTR [rbx] ; get 4th arg
    add rbx, 8
    dec rax
    je  SHORT _do_call

    ; calculate the rest of arguments that need to be pushed on stack
    push rdx  ; save rdx argument
    push rax  ; save the number of arguments
    push rbx  ; save the pointer in buffer
    dec rax
    mov rbx, 8
    mul rbx
    pop rbx
    add rbx, rax  ; rbx should now point to arg buffer
    pop rax  ; restore the number of arguments left in rax
    pop rdx

_load_arg:
    mov r10, QWORD PTR [rbx]
    push r10
    sub rbx, 8
    dec rax
    je  SHORT _do_call
    jmp SHORT _load_arg

_do_call:
    push r9 ; reserve the shadow buffer for registry args native call in 64 bit mode
    push r8 ; just copy the same arguments into it
    push rdx
    push rcx

    mov rax, QWORD PTR dwProcAddr[rbp]
    call rax ; invoke system proc
    
    ; it looks like no cleanup code is needed :), it works well without it...
    mov rdx, QWORD PTR dwNumArgs[rbp] ; calling convention is ignored in 64 bit mode
    mov rcx, rax
    mov rax, rdx
    mov rbx, 8
    mul rbx
    add rsp, rax
    mov rax, rcx

_get_out:
    pop rbx
    mov rsp, rbp
    pop rbp
    ret 0
invoke_sys_proc_x64 ENDP     ; invoke_sys_proc_x64
_TEXT    ENDS


 END